package com.example.demo111.service.impl;

import java.util.List;

public class KnnClassifier
{
	//k个近邻节点
	private int k;
	private KNode[] mNearestK;
	private List<DataNode> mTrainData;

	public KnnClassifier(int k, List<DataNode> trainList)
	{
		mTrainData = trainList;
		this.k = k;
		mNearestK = new KNode[k];
		for (int i = 0; i < k; i++)
			mNearestK[i] = new KNode();
	}
	public void setK(int k){
		this.k = k;
		mNearestK = new KNode[k];
		for (int i = 0; i < k; i++)
			mNearestK[i] = new KNode();
	}
	private void train(DataNode test, float p)
	{
		for (int i = 0; i < mTrainData.size(); i++)
		{
			putNode(getSim(test, mTrainData.get(i), p));
		}
	}

	/**
	 * 将新计算出来的节点与k个近邻节点比较，如果比其中之一小则插入
	 * @param node
	 */
	private void putNode(KNode node)
	{
		for (int i = 0; i < k; i++)
		{
			if (node.getD() < mNearestK[i].getD())
			{
				for (int j = k - 1; j > i; j--)
					mNearestK[j] = mNearestK[j - 1];
				mNearestK[i] = node;
				break;
			}
		}
	}

	/**
	 * 获取相似度并封装成一个KNode类型返回
	 * @param test
	 * @param trainNode
	 * @param p
	 * @return
	 */
	private KNode getSim(DataNode test, DataNode trainNode, float p)
	{
		List<Float> list1 = test.getAttribs();
		List<Float> list2 = trainNode.getAttribs();
		float d = 0;
		for (int i = 0; i < list1.size(); i++)
			d += Math.pow(
					Math.abs(list1.get(i) - list2.get(i)), p);
		d = (float) Math.pow(d, 1/p);
		KNode node = new KNode(d, trainNode.getType());
		return node;
	}

	private void reset()
	{
		for (int i = 0; i < k; i++)
			mNearestK[i].reset();
	}

	/**
	 * 返回K个近邻节点
	 * @param test
	 * @param p
	 * @return
	 */
	public KNode[] getKNN(DataNode test, float p)
	{
		reset();
		train(test, p);
		return mNearestK;
	}
}
